﻿using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Framework.Caching.FreeRedis
{
	public interface IWantDistributedCache
	{
		/// <summary>
		/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <returns>The cache item, or null.</returns>
		TCacheItem Get<TCacheItem, TCacheKey>(
			TCacheKey key,
			string cacheName,
			bool? hideErrors = null,
			bool considerUow = false
		) where TCacheItem : class;

		/// <summary>
		/// Gets multiple cache items with the given keys.
		///
		/// The returned list contains exactly the same count of items specified in the given keys.
		/// An item in the return list can not be null, but an item in the list has null value
		/// if the related key not found in the cache.
		/// </summary>
		/// <param name="keys">The keys of cached items to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <returns>List of cache items.</returns>
		KeyValuePair<TCacheKey, TCacheItem>[] GetMany<TCacheItem, TCacheKey>(
			IEnumerable<TCacheKey> keys,
			string cacheName,
			bool? hideErrors = null,
			bool considerUow = false
		) where TCacheItem : class;

		/// <summary>
		/// Gets multiple cache items with the given keys.
		///
		/// The returned list contains exactly the same count of items specified in the given keys.
		/// An item in the return list can not be null, but an item in the list has null value
		/// if the related key not found in the cache.
		///
		/// </summary>
		/// <param name="keys">The keys of cached items to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// /// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>List of cache items.</returns>
		Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyAsync<TCacheItem, TCacheKey>(
			IEnumerable<TCacheKey> keys,
			string cacheName,
			bool? hideErrors = null,
			bool considerUow = false,
			CancellationToken token = default
		) where TCacheItem : class;

		/// <summary>
		/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>The cache item, or null.</returns>
		Task<TCacheItem> GetAsync<TCacheItem, TCacheKey>(
			[NotNull] TCacheKey key,
			string cacheName,
			bool? hideErrors = null,
			bool considerUow = false,
			CancellationToken token = default
		) where TCacheItem : class;

		/// <summary>
		/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
		/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="factory">The factory delegate is used to provide the cache item when no cache item is found for the given <paramref name="key" />.</param>
		/// <param name="optionsFactory">The cache options for the factory delegate.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <returns>The cache item.</returns>
		TCacheItem GetOrAdd<TCacheItem, TCacheKey>(
			TCacheKey key,
			Func<TCacheItem> factory,
			string cacheName,
			Func<DistributedCacheEntryOptions> optionsFactory = null,
			bool? hideErrors = null,
			bool considerUow = false
		) where TCacheItem : class;

		/// <summary>
		/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
		/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="factory">The factory delegate is used to provide the cache item when no cache item is found for the given <paramref name="key" />.</param>
		/// <param name="optionsFactory">The cache options for the factory delegate.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>The cache item.</returns>
		Task<TCacheItem> GetOrAddAsync<TCacheItem, TCacheKey>(
			[NotNull] TCacheKey key,
			Func<Task<TCacheItem>> factory,
			string cacheName,
			Func<DistributedCacheEntryOptions> optionsFactory = null,
			bool? hideErrors = null,
			bool considerUow = false,
			CancellationToken token = default
		) where TCacheItem : class;

		/// <summary>
		/// Sets the cache item value for the provided key.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="value">The cache item value to set in the cache.</param>
		/// <param name="options">The cache options for the value.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		void Set<TCacheItem, TCacheKey>(
			TCacheKey key,
			TCacheItem value,
			string cacheName,
			DistributedCacheEntryOptions options = null,
			bool? hideErrors = null,
			bool considerUow = false
		) where TCacheItem : class;

		/// <summary>
		/// Sets the cache item value for the provided key.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="value">The cache item value to set in the cache.</param>
		/// <param name="options">The cache options for the value.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
		Task SetAsync<TCacheItem, TCacheKey>(
			[NotNull] TCacheKey key,
			[NotNull] TCacheItem value,
			string cacheName,
			[CanBeNull] DistributedCacheEntryOptions options = null,
			bool? hideErrors = null,
			bool considerUow = false,
			CancellationToken token = default
		) where TCacheItem : class;

		/// <summary>
		/// Sets multiple cache items.
		/// Based on the implementation, this can be more efficient than setting multiple items individually.
		/// </summary>
		/// <param name="items">Items to set on the cache</param>
		/// <param name="options">The cache options for the value.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		void SetMany<TCacheItem, TCacheKey>(
			IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
			string cacheName,
			DistributedCacheEntryOptions options = null,
			bool? hideErrors = null,
			bool considerUow = false
		) where TCacheItem : class;

		/// <summary>
		/// Sets multiple cache items.
		/// Based on the implementation, this can be more efficient than setting multiple items individually.
		/// </summary>
		/// <param name="items">Items to set on the cache</param>
		/// <param name="options">The cache options for the value.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
		Task SetManyAsync<TCacheItem, TCacheKey>(
			IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
			string cacheName,
			DistributedCacheEntryOptions options = null,
			bool? hideErrors = null,
			bool considerUow = false,
			CancellationToken token = default
		) where TCacheItem : class;

		/// <summary>
		/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		void Refresh<TCacheKey>(
			TCacheKey key,
			string cacheName,
			bool? hideErrors = null
		);

		/// <summary>
		/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
		Task RefreshAsync<TCacheKey>(
			TCacheKey key,
			string cacheName,
			bool? hideErrors = null,
			CancellationToken token = default
		);

		/// <summary>
		/// Removes the cache item for given key from cache.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		void Remove<TCacheItem, TCacheKey>(
			TCacheKey key,
			string cacheName,
			bool? hideErrors = null,
			bool considerUow = false
		) where TCacheItem : class;

		/// <summary>
		/// Removes the cache item for given key from cache.
		/// </summary>
		/// <param name="key">The key of cached item to be retrieved from the cache.</param>
		/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
		/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
		/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
		/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
		Task RemoveAsync<TCacheItem, TCacheKey>(
			TCacheKey key,
			string cacheName,
			bool? hideErrors = null,
			bool considerUow = false,
			CancellationToken token = default
		) where TCacheItem : class;
	}
}
